﻿using System;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using Go;

namespace GoRpc
{
    static public partial class Rpc
    {
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
        public sealed class ParamTuple : Attribute
        {
            internal readonly bool Internal;
            internal readonly string Name;

            public ParamTuple(string name)
                : this(name, false) { }

            internal ParamTuple(string name, bool @internal)
            {
                this.Internal = @internal;
                this.Name = name;
            }

            static public void AssertName()
            {
                Serializer.Initialize();
            }
        }

        [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
        public sealed class ParamName : Attribute
        {
            internal readonly string Name;

            public ParamName(string name)
            {
                this.Name = name;
            }
        }

        [ParamTuple("LostTuple", true)]
        abstract public class LostTuple
        {
            DictTuple<object> LostDict;

            internal void AddLost(string name, object value)
            {
                if (LostDict == null)
                {
                    LostDict = new DictTuple<object>();
                }
                LostDict[name] = value;
            }

            public DictTuple<object> Lost
            {
                get
                {
                    return LostDict;
                }
            }
        }

        [ParamTuple("Tuple0", true)] public class Tuple { }
        [ParamTuple("Tuple1", true)] public class Tuple<T1> : Tuple { [ParamName("v1")] public T1 v1; }
        [ParamTuple("Tuple2", true)] public class Tuple<T1, T2> : Tuple<T1> { [ParamName("v2")] public T2 v2; }
        [ParamTuple("Tuple3", true)] public class Tuple<T1, T2, T3> : Tuple<T1, T2> { [ParamName("v3")] public T3 v3; }
        [ParamTuple("Tuple4", true)] public class Tuple<T1, T2, T3, T4> : Tuple<T1, T2, T3> { [ParamName("v4")] public T4 v4; }
        [ParamTuple("Tuple5", true)] public class Tuple<T1, T2, T3, T4, T5> : Tuple<T1, T2, T3, T4> { [ParamName("v5")] public T5 v5; }
        [ParamTuple("Tuple6", true)] public class Tuple<T1, T2, T3, T4, T5, T6> : Tuple<T1, T2, T3, T4, T5> { [ParamName("v6")] public T6 v6; }
        [ParamTuple("Tuple7", true)] public class Tuple<T1, T2, T3, T4, T5, T6, T7> : Tuple<T1, T2, T3, T4, T5, T6> { [ParamName("v7")] public T7 v7; }
        [ParamTuple("Tuple8", true)] public class Tuple<T1, T2, T3, T4, T5, T6, T7, T8> : Tuple<T1, T2, T3, T4, T5, T6, T7> { [ParamName("v8")] public T8 v8; }
        [ParamTuple("Tuple9", true)] public class Tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> : Tuple<T1, T2, T3, T4, T5, T6, T7, T8> { [ParamName("v9")] public T9 v9; }

        private enum GenType
        {
            None,
            Dict,
            Dict2,
            List,
        }

        private interface SerializerDict
        {
            int Count { get; }
            IEnumerator<KeyValuePair<string, object>> GetEnumerator();
            void AddValue(string key, object value);
            Type GetElementType();
        }

        private interface SerializerDict2
        {
            int Count { get; }
            IEnumerator<KeyValuePair<object, object>> GetEnumerator();
            void AddValue(object key, object value);
            TypeCode GetKeyCode();
            Type GetElementType();
        }

        private interface SerializerList
        {
            int Count { get; }
            IEnumerator<object> GetEnumerator();
            void AddValue(object value);
            Type GetElementType();
            void Capacity(int capacity);
        }

        [ParamTuple("DictTuple", true)]
        public sealed class DictTuple<TValue> : Dictionary<string, TValue>, SerializerDict
        {
            IEnumerator<KeyValuePair<string, object>> SerializerDict.GetEnumerator()
            {
                foreach (var item in (Dictionary<string, TValue>)this)
                {
                    yield return new KeyValuePair<string, object>(item.Key, item.Value);
                }
                yield break;
            }

            void SerializerDict.AddValue(string key, object value)
            {
                this[key] = (TValue)value;
            }

            Type SerializerDict.GetElementType()
            {
                return typeof(TValue);
            }
        }

        [ParamTuple("Dict2Tuple", true)]
        public sealed class DictTuple<TKey, TValue> : Dictionary<TKey, TValue>, SerializerDict2 where TKey : unmanaged
        {
            IEnumerator<KeyValuePair<object, object>> SerializerDict2.GetEnumerator()
            {
                foreach (var item in (Dictionary<TKey, TValue>)this)
                {
                    yield return new KeyValuePair<object, object>(item.Key, item.Value);
                }
                yield break;
            }

            void SerializerDict2.AddValue(object key, object value)
            {
                this[(TKey)key] = (TValue)value;
            }

            TypeCode SerializerDict2.GetKeyCode()
            {
                return Type.GetTypeCode(typeof(TKey));
            }

            Type SerializerDict2.GetElementType()
            {
                return typeof(TValue);
            }
        }

        [ParamTuple("ListTuple", true)]
        public sealed class ListTuple<TValue> : List<TValue>, SerializerList
        {
            public ListTuple() : base() { }
            public ListTuple(int capacity) : base(capacity) { }

            IEnumerator<object> SerializerList.GetEnumerator()
            {
                foreach (var item in (List<TValue>)this)
                {
                    yield return item;
                }
                yield break;
            }

            void SerializerList.AddValue(object value)
            {
                Add((TValue)value);
            }

            Type SerializerList.GetElementType()
            {
                return typeof(TValue);
            }

            void SerializerList.Capacity(int capacity)
            {
                this.Capacity = capacity;
            }
        }

        [ParamTuple("LinkedListTuple", true)]
        public sealed class LinkedListTuple<TValue> : LinkedList<TValue>, SerializerList
        {
            IEnumerator<object> SerializerList.GetEnumerator()
            {
                foreach (var item in (LinkedList<TValue>)this)
                {
                    yield return item;
                }
                yield break;
            }

            void SerializerList.AddValue(object value)
            {
                AddLast((TValue)value);
            }

            Type SerializerList.GetElementType()
            {
                return typeof(TValue);
            }

            void SerializerList.Capacity(int capacity)
            {
            }
        }

        [ParamTuple("MapListTuple", true)]
        public sealed class MapListTuple<TValue> : MapList<TValue>, SerializerList
        {
            IEnumerator<object> SerializerList.GetEnumerator()
            {
                foreach (var item in (MapList<TValue>)this)
                {
                    yield return item;
                }
                yield break;
            }

            void SerializerList.AddValue(object value)
            {
                AddLast((TValue)value);
            }

            Type SerializerList.GetElementType()
            {
                return typeof(TValue);
            }

            void SerializerList.Capacity(int capacity)
            {
            }
        }

        private class SerializationException : Exception
        {
            public SerializationException(string typeName, string assemblyName, Exception innerException = null)
                : base($"无法序列化类型: {typeName} (程序集: {assemblyName})", innerException) { }
        }

        private class DeserializeException : Exception
        {
            public DeserializeException(string typeName, string assemblyName, Exception innerException = null)
                : base($"无法反序列化类型: {typeName} (程序集: {assemblyName})", innerException) { }
        }

        unsafe class Serializer
        {
            struct TypeInfo
            {
                static private string[] ArrayTails = new string[]
                {
                    "",
                    "[]",
                    "[,]",
                    "[,,]",
                    "[,,,]",
                };

                public string TypeName;

                public TypeInfo(Type type)
                {
                    TypeName = ParseType(type);
                }

                static private string ParseType(Type type)
                {
                    Type baseType = type;
                    bool isArray = type.IsArray;
                    bool arrayIt = baseType.IsArray;
                    while (arrayIt)
                    {
                        int rank = type.GetArrayRank();
                        if (rank >= ArrayTails.Length)
                        {
                            throw new SerializationException($"{type.FullName} Rank错误", type.Assembly.FullName);
                        }
                        baseType = baseType.GetElementType();
                        if (baseType == null)
                        {
                            throw new SerializationException($"{type.FullName} 错误", type.Assembly.FullName);
                        }
                        arrayIt = baseType.IsArray;
                    }
                    ParamTuple nameAttr = (ParamTuple)Attribute.GetCustomAttribute(baseType, typeof(ParamTuple), false);
                    if (null == nameAttr)
                    {
                        switch (Type.GetTypeCode(baseType))
                        {
                            case TypeCode.Boolean:
                            case TypeCode.Char:
                            case TypeCode.SByte:
                            case TypeCode.Byte:
                            case TypeCode.Int16:
                            case TypeCode.UInt16:
                            case TypeCode.Int32:
                            case TypeCode.UInt32:
                            case TypeCode.Int64:
                            case TypeCode.UInt64:
                            case TypeCode.Single:
                            case TypeCode.Double:
                            case TypeCode.Decimal:
                            case TypeCode.DateTime:
                            case TypeCode.String:
                                return type.FullName;
                            case TypeCode.Object:
                                if (baseType == typeof(object))
                                {
                                    return type.FullName;
                                }
                                break;
                        }
                        throw new SerializationException($"{type.FullName} 错误", type.Assembly.FullName);
                    }
                    string tapeName;
                    string attrName = string.Concat(baseType.Namespace, ".", nameAttr.Name);
                    if (baseType.IsGenericType)
                    {
                        Type[] genericTypes = baseType.GetGenericArguments();
                        for (int i = 0; i < genericTypes.Length; i++)
                        {
                            attrName = string.Concat(attrName, "<", ParseType(genericTypes[i]), ">");
                        }
                    }
                    if (isArray)
                    {
                        string typeName = type.FullName;
                        int firstBracket = FirstArrayBracket(typeName);
                        int len1 = attrName.Length;
                        int len2 = typeName.Length - firstBracket;
                        tapeName = new string('\0', len1 + len2);
                        fixed (char* dst_ = tapeName)
                        {
                            char* dst = dst_;
                            fixed (char* src_ = attrName)
                            {
                                char* src = src_;
                                for (int i = len1; i > 0; i--)
                                {
                                    *(dst++) = *(src++);
                                }
                            }
                            fixed (char* src_ = typeName)
                            {
                                char* src = src_ + firstBracket;
                                for (int i = len2; i > 0; i--)
                                {
                                    *(dst++) = *(src++);
                                }
                            }
                        }
                    }
                    else
                    {
                        tapeName = attrName;
                    }
                    return tapeName;
                }

                public bool IsNull
                {
                    get
                    {
                        return string.IsNullOrEmpty(TypeName);
                    }
                }

                public bool LikeArray
                {
                    get
                    {
                        return TypeName[TypeName.Length - 1] == ']';
                    }
                }

                public int ArrayDeep
                {
                    get
                    {
                        if (!LikeArray)
                        {
                            return 0;
                        }
                        int deep = 0;
                        bool sign = false;
                        fixed (char* dst_ = TypeName)
                        {
                            int len = TypeName.Length;
                            char* dst = dst_ + len;
                            for (int i = 0; i < len; i++)
                            {
                                switch (*(--dst))
                                {
                                    case '[':
                                        if (!sign)
                                        {
                                            return deep;
                                        }
                                        deep++;
                                        continue;
                                    case ']':
                                        if (sign)
                                        {
                                            return deep;
                                        }
                                        sign = true;
                                        continue;
                                    case ',':
                                        if (!sign)
                                        {
                                            return deep;
                                        }
                                        continue;
                                    default:
                                        return deep;
                                }
                            }
                        }
                        return deep;
                    }
                }

                static private int FirstArrayBracket(string name)
                {
                    int start = -1;
                    bool sign = false;
                    fixed (char* dst_ = name)
                    {
                        int len = name.Length;
                        char* dst = dst_ + len;
                        for (int i = 0; i < len; i++)
                        {
                            switch (*(--dst))
                            {
                                case '[':
                                    if (!sign)
                                    {
                                        return start;
                                    }
                                    sign = false;
                                    start = len - i - 1;
                                    continue;
                                case ']':
                                    if (sign)
                                    {
                                        return start;
                                    }
                                    sign = true;
                                    continue;
                                case ',':
                                    if (!sign)
                                    {
                                        return start;
                                    }
                                    continue;
                                default:
                                    return start;
                            }
                        }
                    }
                    return start;
                }

                public int FirstBracket
                {
                    get
                    {
                        if (!LikeArray)
                        {
                            return -1;
                        }
                        return FirstArrayBracket(TypeName);
                    }
                }

                public int ArrayRank
                {
                    get
                    {
                        if (!LikeArray)
                        {
                            return 0;
                        }
                        int lastBracket = TypeName.LastIndexOf("[");
                        if (lastBracket == -1)
                        {
                            return -1;
                        }
                        int rank = TypeName.Length - lastBracket - 1;
                        if (rank <= 0 || rank >= ArrayTails.Length)
                        {
                            return -1;
                        }
                        string tail = ArrayTails[rank];
                        for (int i = 0; i <= rank; i++)
                        {
                            if (TypeName[lastBracket + i] != tail[i])
                            {
                                return -1;
                            }
                        }
                        return rank;
                    }
                }

                public string ElementName
                {
                    get
                    {
                        if (!LikeArray)
                        {
                            return null;
                        }
                        int lastBracket = TypeName.LastIndexOf("[");
                        if (lastBracket == -1)
                        {
                            return null;
                        }
                        return TypeName.Substring(0, lastBracket);
                    }
                }
            }

            struct MemberInfo
            {
                public string MemberName;
                public Func<object, object> GetValue;
                public Action<object, object> SetValue;
                public Type MemberType;
            }

            class MembersInfo
            {
                public bool IsInternal;
                public bool IsLostTuple;
                public int TupleSize;
                public GenType GenType;
                public Func<object> New;
                public MemberInfo[] Members;
            }

            class NameType
            {
                public Type Type;
                public int Rank;
                public bool GenUndefined;
                public string[] GenNames;
                public string ElementName;

                public NameType(string name, Type type, string[] genNames, bool genUndefined)
                {
                    Type = type;
                    GenNames = genNames;
                    GenUndefined = genUndefined;
                    var typeInfo = new TypeInfo { TypeName = name };
                    var deep = typeInfo.ArrayDeep;
                    if (deep > 4)
                    {
                        throw new DeserializeException("数组异常", "");
                    }
                    Rank = typeInfo.ArrayRank;
                    if (Rank != 0)
                    {
                        if (Rank < 0 || Rank > 4)
                        {
                            throw new DeserializeException("数组异常", "");
                        }
                        if (deep <= 0)
                        {
                            throw new DeserializeException("未知异常", "");
                        }
                        ElementName = typeInfo.ElementName;
                        if (ElementName == null)
                        {
                            throw new DeserializeException("数组异常", "");
                        }
                    }
                }
            }

            struct CacheNode<K, V>
            {
                public K Key;
                public V Value;
            }

            class CacheQueue<Key, Value>
            {
                public int FixCount;
                public LinkedList<CacheNode<Key, Value>> Queue = new LinkedList<CacheNode<Key, Value>>();
                public ConcurrentDictionary<Key, LinkedListNode<CacheNode<Key, Value>>> Cache = new ConcurrentDictionary<Key, LinkedListNode<CacheNode<Key, Value>>>();
            }

            private const int _maxCache = 10000;
            static private bool _initialized = false;
            static private readonly CacheQueue<string, NameType> _nameTypeCache = new CacheQueue<string, NameType>();
            static private readonly CacheQueue<Type, MembersInfo> _memberCache = new CacheQueue<Type, MembersInfo>();
            static private readonly ConcurrentDictionary<Type, TypeInfo> _typeInfoCache = new ConcurrentDictionary<Type, TypeInfo>();
            static private readonly Func<Type, bool, int> SizeOf = (Func<Type, bool, int>)Delegate.CreateDelegate(typeof(Func<Type, bool, int>), typeof(Marshal).GetMethod("SizeOfHelper", BindingFlags.Static | BindingFlags.NonPublic));
            static private readonly void_type _init = functional.init(delegate ()
            {
                Initialize();
                return default(void_type);
            });

            static private GenType CheckGenericTuple(Type type)
            {
                if (type.IsGenericType)
                {
                    Type gtype = type.GetGenericTypeDefinition();
                    if (gtype == typeof(DictTuple<>))
                    {
                        return GenType.Dict;
                    }
                    else if (gtype == typeof(DictTuple<,>))
                    {
                        return GenType.Dict2;
                    }
                    else if (gtype == typeof(ListTuple<>))
                    {
                        return GenType.List;
                    }
                    else if (gtype == typeof(LinkedListTuple<>))
                    {
                        return GenType.List;
                    }
                    else if (gtype == typeof(MapListTuple<>))
                    {
                        return GenType.List;
                    }
                }
                return GenType.None;
            }

            static private bool TryGetCache<Key, Value>(CacheQueue<Key, Value> cache, Key key, out Value value, bool update = true)
            {
                if (cache.Cache.TryGetValue(key, out var oldNode))
                {
                    value = oldNode.Value.Value;
                    if (update && (cache.Cache.Count - cache.FixCount) > (_maxCache >> 1) && oldNode.List != null)
                    {
                        lock (cache.Queue)
                        {
                            if (oldNode.List != null)
                            {
                                cache.Queue.Remove(oldNode);
                                cache.Queue.AddLast(oldNode);
                            }
                        }
                    }
                    return true;
                }
                value = default;
                return false;
            }

            static private void TryAddCache<Key, Value>(CacheQueue<Key, Value> cache, Key key, Value value, bool update = true)
            {
                var newNode = new LinkedListNode<CacheNode<Key, Value>>(new CacheNode<Key, Value> { Key = key, Value = value });
                if (!update)
                {
                    cache.Cache.TryAdd(key, newNode);
                    return;
                }
                lock (cache.Queue)
                {
                    cache.Queue.AddLast(newNode);
                }
                if (cache.Cache.TryAdd(key, newNode))
                {
                    while ((cache.Cache.Count - cache.FixCount) > _maxCache)
                    {
                        Key oldKey = default;
                        lock (cache.Queue)
                        {
                            var firstNode = cache.Queue.First;
                            if (firstNode == null)
                            {
                                return;
                            }
                            oldKey = firstNode.Value.Key;
                            cache.Queue.Remove(firstNode);
                        }
                        cache.Cache.TryRemove(oldKey, out var _);
                    }
                }
                else
                {
                    lock (cache.Queue)
                    {
                        if (newNode.List != null)
                        {
                            cache.Queue.Remove(newNode);
                        }
                    }
                }
            }

            static private List<tuple<FieldInfo, string>> GetFields(Type type)
            {
                var allFields = new List<tuple<FieldInfo, string>>(255);
                var typeIt = type;
                while (typeIt != null)
                {
                    var fields = typeIt.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
                    for (int i = 0; i < fields.Length; i++)
                    {
                        var fieldNameAttr = (ParamName)Attribute.GetCustomAttribute(fields[i], typeof(ParamName), false);
                        if (fieldNameAttr == null)
                        {
                            continue;
                        }
                        allFields.Add(tuple.make(fields[i], fieldNameAttr.Name));
                    }
                    typeIt = typeIt.BaseType;
                }
                return allFields;
            }

            static private List<tuple<PropertyInfo, string>> GetProperties(Type type)
            {
                var allProperties = new List<tuple<PropertyInfo, string>>(255);
                var typeIt = type;
                while (typeIt != null)
                {
                    var properties = typeIt.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
                    for (int i = 0; i < properties.Length; i++)
                    {
                        var propertyNameAttr = (ParamName)Attribute.GetCustomAttribute(properties[i], typeof(ParamName), false);
                        if (propertyNameAttr == null)
                        {
                            continue;
                        }
                        allProperties.Add(tuple.make(properties[i], propertyNameAttr.Name));
                    }
                    typeIt = typeIt.BaseType;
                }
                return allProperties;
            }

            static internal void Initialize()
            {
                if (_initialized)
                {
                    return;
                }
                lock (_nameTypeCache.Cache)
                {
                    if (_initialized)
                    {
                        return;
                    }
                    assert.check(BitConverter.IsLittleEndian, "");
                    Type[] baseTypes = new Type[]
                    {
                        typeof(bool),
                        typeof(byte),
                        typeof(sbyte),
                        typeof(char),
                        typeof(short),
                        typeof(ushort),
                        typeof(int),
                        typeof(uint),
                        typeof(long),
                        typeof(ulong),
                        typeof(float),
                        typeof(double),
                        typeof(decimal),
                        typeof(string),
                        typeof(object),
                        typeof(DateTime),
                    };
                    foreach (var type in baseTypes)
                    {
                        string attrName = type.FullName;
                        TryAddCache(_nameTypeCache, attrName, new NameType(attrName, type, null, false), false);
                        Type arrType = type;
                        string arrName = attrName;
                        for (int i = 0; i < 4; i++)
                        {
                            arrName += "[]";
                            arrType = arrType.MakeArrayType();
                            TryAddCache(_nameTypeCache, arrName, new NameType(arrName, arrType, null, false), false);
                        }
                    }
                    var tupleNameDict = new ConcurrentDictionary<string, void_type>();
                    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
                    {
                        try
                        {
                            foreach (var type in assembly.GetTypes())
                            {
                                var nameAttr = (ParamTuple)Attribute.GetCustomAttribute(type, typeof(ParamTuple), false);
                                if (nameAttr == null)
                                {
                                    continue;
                                }
                                if (!type.IsValueType)
                                {
                                    bool isInternal = nameAttr.Internal;
                                    Type baseType = type.BaseType;
                                    while (baseType != typeof(object))
                                    {
                                        bool definedParamTuple = Attribute.IsDefined(baseType, typeof(ParamTuple), false);
                                        assert.check(definedParamTuple || isInternal, $"Rpc.ParamTuple 继承于非 Rpc.ParamTuple 类\r\n\r\n{type.Assembly.FullName}.{type.FullName}");
                                        baseType = baseType.BaseType;
                                    }
                                    var constructors = type.GetConstructors();
                                    if (constructors.Length != 0)
                                    {
                                        bool existDefault = false;
                                        foreach (var item in constructors)
                                        {
                                            if (item.GetParameters().Length == 0)
                                            {
                                                existDefault = true;
                                                break;
                                            }
                                        }
                                        if (!existDefault)
                                        {
                                            assert.check(false, $"Rpc.ParamTuple 未定义默认构造方法\r\n\r\n{type.Assembly.FullName}.{type.FullName}");
                                        }
                                    }
                                }
                                var typeName = nameAttr.Name;
                                if (string.IsNullOrEmpty(typeName))
                                {
                                    assert.check(false, $"Rpc.ParamTuple 类名称未定义\r\n\r\n{type.Assembly.FullName}.{type.FullName}");
                                }
                                if (typeName.Length > 255)
                                {
                                    assert.check(false, $"Rpc.ParamTuple 类名称长度错误\r\n\r\n{type.Assembly.FullName}.{type.FullName}");
                                }
                                assert.check(Methods.CheckName(typeName), $"Rpc.ParamTuple 类命名错误 {typeName}\r\n\r\n{type.Assembly.FullName}.{type.FullName}");
                                typeName = string.Concat(type.Namespace, ".", typeName);
                                if (!tupleNameDict.TryAdd(typeName, default))
                                {
                                    assert.check(false, $"Rpc.ParamTuple 类名称 {typeName} 重复\r\n\r\n{type.Assembly.FullName}.{type.FullName}");
                                }
                                TryAddCache(_nameTypeCache, typeName, new NameType(typeName, type, new string[type.GetGenericArguments().Length], false), false);
                                var fields = GetFields(type);
                                var properties = GetProperties(type);
                                if (fields.Count + properties.Count > 255)
                                {
                                    assert.check(false, $"Rpc.ParamTuple 元素数量异常({fields.Count + properties.Count})\r\n\r\n{type.Assembly.FullName}.{type.FullName}");
                                }
                                var fieldNameDict = new ConcurrentDictionary<string, void_type>();
                                var nameDict = new ConcurrentDictionary<string, void_type>();
                                for (int i = 0; i < fields.Count; i++)
                                {
                                    var fieldType = fields[i].value1.FieldType;
                                    if (!fieldType.IsGenericParameter && !CheckType(fieldType, out bool _))
                                    {
                                        throw new SerializationException($"{type.FullName}.{fields[i].value1.Name}", type.Assembly.FullName);
                                    }
                                    var fieldName = fields[i].value2;
                                    if (string.IsNullOrEmpty(fieldName))
                                    {
                                        assert.check(false, $"Rpc.ParamTuple 字段名称未定义\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{fields[i].value1.Name}");
                                    }
                                    if (fieldName.Length > 255)
                                    {
                                        assert.check(false, $"Rpc.ParamTuple 字段名称长度错误\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{fields[i].value1.Name}");
                                    }
                                    assert.check(Methods.CheckName(fieldName), $"Rpc.ParamTuple 字段名称错误 {fieldName}\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{fields[i].value1.Name}");
                                    if (!nameDict.TryAdd(fieldName, default))
                                    {
                                        assert.check(false, $"Rpc.ParamTuple 定义字段名称 {fieldName} 重复\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{fields[i].value1.Name}");
                                    }
                                    if (!fieldNameDict.TryAdd(fieldName, default))
                                    {
                                        assert.check(false, $"Rpc.ParamTuple 定义字段名称 {fieldName} 重复\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{fields[i].value1.Name}");
                                    }
                                }
                                for (int i = 0; i < properties.Count; i++)
                                {
                                    var propertyType = properties[i].value1.PropertyType;
                                    if (!propertyType.IsGenericParameter && !CheckType(propertyType, out bool isBaseType))
                                    {
                                        throw new SerializationException($"{type.FullName}.{properties[i].value1.Name}", type.Assembly.FullName);
                                    }
                                    string propertyName = properties[i].value2;
                                    if (string.IsNullOrEmpty(propertyName))
                                    {
                                        assert.check(false, $"Rpc.ParamTuple 属性名称未定义\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{properties[i].value1.Name}");
                                    }
                                    if (propertyName.Length > 255)
                                    {
                                        assert.check(false, $"Rpc.ParamTuple 属性名称长度错误\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{properties[i].value1.Name}");
                                    }
                                    assert.check(Methods.CheckName(propertyName), $"Rpc.ParamTuple 属性名称错误 {propertyName}\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{properties[i].value1.Name}");
                                    if (!nameDict.TryAdd(propertyName, default))
                                    {
                                        assert.check(false, $"Rpc.ParamTuple 定义属性名称 {propertyName} 重复\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{properties[i].value1.Name}");
                                    }
                                    if (!fieldNameDict.TryAdd(propertyName, default))
                                    {
                                        assert.check(false, $"Rpc.ParamTuple 定义属性名称 {propertyName} 重复\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{properties[i].value1.Name}");
                                    }
                                    if (properties[i].value1.GetGetMethod(true) == null)
                                    {
                                        assert.check(false, $"Rpc.ParamTuple 属性 {propertyName} 未定义 Getter\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{properties[i].value1.Name}");
                                    }
                                    if (properties[i].value1.GetSetMethod(true) == null)
                                    {
                                        assert.check(false, $"Rpc.ParamTuple 属性 {propertyName} 未定义 Setter\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{properties[i].value1.Name}");
                                    }
                                }
                                if (type.IsGenericType || type.IsAbstract)
                                {
                                    continue;
                                }
                                _typeInfoCache.TryAdd(type, new TypeInfo(type));
                                Type arrType = type;
                                string arrName = typeName;
                                for (int i = 0; i < 4; i++)
                                {
                                    arrName += "[]";
                                    arrType = arrType.MakeArrayType();
                                    TryAddCache(_nameTypeCache, arrName, new NameType(arrName, arrType, null, false), false);
                                    _typeInfoCache.TryAdd(arrType, new TypeInfo(arrType));
                                }
                                GetMembersInfo(type, false);
                            }
                        }
                        catch (ReflectionTypeLoadException)
                        {
                            assert.check(false, $"{assembly.FullName} Rpc.ParamTuple 加载失败");
                        }
                        catch (SerializationException ec)
                        {
                            assert.check(false, ec.Message);
                        }
                    }
                    _nameTypeCache.FixCount = _nameTypeCache.Cache.Count;
                    _memberCache.FixCount = _memberCache.Cache.Count;
                    _initialized = true;
                }
            }

            private int origin;
            private bool matchMember;
            private MemoryStream stream;
            private BinaryWriter writer;
            private BinaryReader reader;

            public Serializer(byte[] buffer, int origin, int count, bool matchMember)
            {
                if (buffer == null)
                    throw new ArgumentNullException(nameof(buffer));
                this.origin = origin;
                this.matchMember = matchMember;
                stream = new MemoryStream(buffer, origin, count, true, true);
                writer = new BinaryWriter(stream);
                reader = new BinaryReader(stream);
            }

            #region
            public byte[] Buffer
            {
                get { return stream.GetBuffer(); }
            }

            public int Position
            {
                get { return (int)stream.Position; }
                set { stream.Position = value; }
            }

            static private void CopyBytes(byte* dst, byte* src, int length)
            {
                for (int i = length; i > 0; i--)
                {
                    *(dst++) = *(src++);
                }
            }

            private void WriteBytes<T>(T* array, int length) where T : unmanaged
            {
                byte[] dstBuf = stream.GetBuffer();
                int pos = (int)stream.Position;
                int dstOrg = origin + pos;
                int dstLen = dstBuf.Length - dstOrg;
                int srcLen = length * sizeof(T);
                if (srcLen > dstLen)
                    throw new IOException("写入流长度溢出");
                fixed (byte* dst = dstBuf)
                    CopyBytes(dst + dstOrg, (byte*)array, srcLen);
                stream.Position = pos + srcLen;
            }

            private void ReadBytes<T>(T* array, int length) where T : unmanaged
            {
                byte[] srcBuf = stream.GetBuffer();
                int pos = (int)stream.Position;
                int srcOrg = origin + pos;
                int srcLen = srcBuf.Length - srcOrg;
                int dstLen = length * sizeof(T);
                if (dstLen > srcLen)
                    throw new IOException("读取流长度溢出");
                fixed (byte* src = srcBuf)
                    CopyBytes((byte*)array, src + srcOrg, dstLen);
                stream.Position = pos + dstLen;
            }

            private void WriteBytes1D<T>(T[] array, int length) where T : unmanaged
            {
                fixed (T* src = array) WriteBytes(src, length);
            }

            private void ReadBytes1D<T>(T[] array, int length) where T : unmanaged
            {
                fixed (T* dst = array) ReadBytes(dst, length);
            }

            private void WriteBytes2D<T>(T[,] array, int length) where T : unmanaged
            {
                fixed (T* src = array) WriteBytes(src, length);
            }

            private void ReadBytes2D<T>(T[,] array, int length) where T : unmanaged
            {
                fixed (T* dst = array) ReadBytes(dst, length);
            }

            private void WriteBytes3D<T>(T[,,] array, int length) where T : unmanaged
            {
                fixed (T* src = array) WriteBytes(src, length);
            }

            private void ReadBytes3D<T>(T[,,] array, int length) where T : unmanaged
            {
                fixed (T* dst = array) ReadBytes(dst, length);
            }

            private void WriteBytes4D<T>(T[,,,] array, int length) where T : unmanaged
            {
                fixed (T* src = array) WriteBytes(src, length);
            }

            private void ReadBytes4D<T>(T[,,,] array, int length) where T : unmanaged
            {
                fixed (T* dst = array) ReadBytes(dst, length);
            }

            private bool WriteBytesMD(Array array, Type elementType, int rank)
            {
                int length = array.Length;
                switch (Type.GetTypeCode(elementType))
                {
                    case TypeCode.Boolean:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((bool[])array, length); return true;
                            case 2: WriteBytes2D((bool[,])array, length); return true;
                            case 3: WriteBytes3D((bool[,,])array, length); return true;
                            case 4: WriteBytes4D((bool[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Char:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((char[])array, length); return true;
                            case 2: WriteBytes2D((char[,])array, length); return true;
                            case 3: WriteBytes3D((char[,,])array, length); return true;
                            case 4: WriteBytes4D((char[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.SByte:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((sbyte[])array, length); return true;
                            case 2: WriteBytes2D((sbyte[,])array, length); return true;
                            case 3: WriteBytes3D((sbyte[,,])array, length); return true;
                            case 4: WriteBytes4D((sbyte[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Byte:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((byte[])array, length); return true;
                            case 2: WriteBytes2D((byte[,])array, length); return true;
                            case 3: WriteBytes3D((byte[,,])array, length); return true;
                            case 4: WriteBytes4D((byte[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Int16:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((short[])array, length); return true;
                            case 2: WriteBytes2D((short[,])array, length); return true;
                            case 3: WriteBytes3D((short[,,])array, length); return true;
                            case 4: WriteBytes4D((short[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.UInt16:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((ushort[])array, length); return true;
                            case 2: WriteBytes2D((ushort[,])array, length); return true;
                            case 3: WriteBytes3D((ushort[,,])array, length); return true;
                            case 4: WriteBytes4D((ushort[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Int32:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((int[])array, length); return true;
                            case 2: WriteBytes2D((int[,])array, length); return true;
                            case 3: WriteBytes3D((int[,,])array, length); return true;
                            case 4: WriteBytes4D((int[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.UInt32:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((uint[])array, length); return true;
                            case 2: WriteBytes2D((uint[,])array, length); return true;
                            case 3: WriteBytes3D((uint[,,])array, length); return true;
                            case 4: WriteBytes4D((uint[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Int64:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((long[])array, length); return true;
                            case 2: WriteBytes2D((long[,])array, length); return true;
                            case 3: WriteBytes3D((long[,,])array, length); return true;
                            case 4: WriteBytes4D((long[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.UInt64:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((ulong[])array, length); return true;
                            case 2: WriteBytes2D((ulong[,])array, length); return true;
                            case 3: WriteBytes3D((ulong[,,])array, length); return true;
                            case 4: WriteBytes4D((ulong[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Single:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((float[])array, length); return true;
                            case 2: WriteBytes2D((float[,])array, length); return true;
                            case 3: WriteBytes3D((float[,,])array, length); return true;
                            case 4: WriteBytes4D((float[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Double:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((double[])array, length); return true;
                            case 2: WriteBytes2D((double[,])array, length); return true;
                            case 3: WriteBytes3D((double[,,])array, length); return true;
                            case 4: WriteBytes4D((double[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Decimal:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((decimal[])array, length); return true;
                            case 2: WriteBytes2D((decimal[,])array, length); return true;
                            case 3: WriteBytes3D((decimal[,,])array, length); return true;
                            case 4: WriteBytes4D((decimal[,,,])array, length); return true;
                            default: return false;
                        }
                    default:
                        return false;
                }
            }

            private bool ReadBytesMD(Array array, Type elementType, int rank)
            {
                int length = array.Length;
                switch (Type.GetTypeCode(elementType))
                {
                    case TypeCode.Boolean:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((bool[])array, length); return true;
                            case 2: ReadBytes2D((bool[,])array, length); return true;
                            case 3: ReadBytes3D((bool[,,])array, length); return true;
                            case 4: ReadBytes4D((bool[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Char:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((char[])array, length); return true;
                            case 2: ReadBytes2D((char[,])array, length); return true;
                            case 3: ReadBytes3D((char[,,])array, length); return true;
                            case 4: ReadBytes4D((char[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.SByte:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((sbyte[])array, length); return true;
                            case 2: ReadBytes2D((sbyte[,])array, length); return true;
                            case 3: ReadBytes3D((sbyte[,,])array, length); return true;
                            case 4: ReadBytes4D((sbyte[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Byte:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((byte[])array, length); return true;
                            case 2: ReadBytes2D((byte[,])array, length); return true;
                            case 3: ReadBytes3D((byte[,,])array, length); return true;
                            case 4: ReadBytes4D((byte[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Int16:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((short[])array, length); return true;
                            case 2: ReadBytes2D((short[,])array, length); return true;
                            case 3: ReadBytes3D((short[,,])array, length); return true;
                            case 4: ReadBytes4D((short[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.UInt16:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((ushort[])array, length); return true;
                            case 2: ReadBytes2D((ushort[,])array, length); return true;
                            case 3: ReadBytes3D((ushort[,,])array, length); return true;
                            case 4: ReadBytes4D((ushort[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Int32:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((int[])array, length); return true;
                            case 2: ReadBytes2D((int[,])array, length); return true;
                            case 3: ReadBytes3D((int[,,])array, length); return true;
                            case 4: ReadBytes4D((int[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.UInt32:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((uint[])array, length); return true;
                            case 2: ReadBytes2D((uint[,])array, length); return true;
                            case 3: ReadBytes3D((uint[,,])array, length); return true;
                            case 4: ReadBytes4D((uint[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Int64:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((long[])array, length); return true;
                            case 2: ReadBytes2D((long[,])array, length); return true;
                            case 3: ReadBytes3D((long[,,])array, length); return true;
                            case 4: ReadBytes4D((long[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.UInt64:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((ulong[])array, length); return true;
                            case 2: ReadBytes2D((ulong[,])array, length); return true;
                            case 3: ReadBytes3D((ulong[,,])array, length); return true;
                            case 4: ReadBytes4D((ulong[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Single:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((float[])array, length); return true;
                            case 2: ReadBytes2D((float[,])array, length); return true;
                            case 3: ReadBytes3D((float[,,])array, length); return true;
                            case 4: ReadBytes4D((float[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Double:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((double[])array, length); return true;
                            case 2: ReadBytes2D((double[,])array, length); return true;
                            case 3: ReadBytes3D((double[,,])array, length); return true;
                            case 4: ReadBytes4D((double[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Decimal:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((decimal[])array, length); return true;
                            case 2: ReadBytes2D((decimal[,])array, length); return true;
                            case 3: ReadBytes3D((decimal[,,])array, length); return true;
                            case 4: ReadBytes4D((decimal[,,,])array, length); return true;
                            default: return false;
                        }
                    default:
                        return false;
                }
            }

            private void WriteName(string name)
            {
                int srcLen = name.Length;
                uint num = (uint)srcLen;
                for (; num >= 128; num >>= 7)
                {
                    writer.Write((byte)(num | 0x80u));
                }
                writer.Write((byte)num);
                byte[] dstBuf = stream.GetBuffer();
                int pos = (int)stream.Position;
                int dstOrg = origin + pos;
                int dstLen = dstBuf.Length - dstOrg;
                if (srcLen > dstLen)
                    throw new IOException("写入流长度溢出");
                fixed (char* src_ = name)
                {
                    char* src = src_;
                    fixed (byte* dst_ = dstBuf)
                    {
                        byte* dst = dst_ + dstOrg;
                        for (int i = 0; i < srcLen; i++)
                        {
                            *(dst++) = (byte)*(src++);
                        }
                    }
                }
                stream.Position = pos + srcLen;
            }

            private string ReadName()
            {
                int dstLen = 0;
                int bits = 0;
                byte b;
                do
                {
                    if (bits == 35)
                    {
                        throw new IOException("Format_Bad7BitInt32");
                    }
                    b = reader.ReadByte();
                    dstLen |= (b & 0x7F) << bits;
                    bits += 7;
                }
                while ((b & 0x80u) != 0);
                byte[] srcBuf = stream.GetBuffer();
                int pos = (int)stream.Position;
                int srcOrg = origin + pos;
                int srcLen = srcBuf.Length - srcOrg;
                if (dstLen > srcLen)
                    throw new IOException("读取流长度溢出");
                string name = new string('\0', dstLen);
                fixed (char* dst_ = name)
                {
                    char* dst = dst_;
                    fixed (byte* src_ = srcBuf)
                    {
                        byte* src = src_ + srcOrg;
                        for (int i = 0; i < dstLen; i++)
                        {
                            *(dst++) = (char)*(src++);
                        }
                    }
                }
                stream.Position = pos + dstLen;
                return name;
            }
            #endregion

            internal int SerializeRequest(Session.Request request)
            {
                writer.Write(request.reply);
                WriteName(request.name);
                var sends = request.sends;
                if (sends == null || sends.Length == 0)
                {
                    writer.Write(ushort.MinValue);
                }
                else if (sends.Length <= ushort.MaxValue)
                {
                    writer.Write((ushort)sends.Length);
                    for (int i = 0; i < sends.Length; i++)
                    {
                        writer.Write(sends[i].id);
                        writer.Write(sends[i].count);
                        writer.Write(sends[i].segment);
                    }
                }
                else
                {
                    throw new SerializationException("Session.Request错误", "");
                }
                return (int)stream.Position;
            }

            internal int SerializeReply(Session.Reply reply)
            {
                writer.Write((byte)reply.state);
                if (string.IsNullOrEmpty(reply.message))
                {
                    writer.Write((byte)0);
                }
                else
                {
                    writer.Write(reply.message);
                }
                return (int)stream.Position;
            }

            internal Session.Request DeserializeRequest()
            {
                Session.Request request = new Session.Request();
                request.reply = reader.ReadBoolean();
                request.name = ReadName();
                var sends = reader.ReadUInt16();
                if (sends != ushort.MinValue)
                {
                    request.sends = new RecvName[sends];
                    for (int i = 0; i < sends; i++)
                    {
                        request.sends[i].id = reader.ReadInt64();
                        request.sends[i].count = reader.ReadInt64();
                        request.sends[i].segment = reader.ReadInt32();
                    }
                }
                return request;
            }

            internal Session.Reply DeserializeReply()
            {
                Session.Reply reply = new Session.Reply();
                reply.state = (ReplyState)reader.ReadByte();
                int pos = (int)stream.Position;
                if (stream.GetBuffer()[pos] == 0)
                {
                    stream.Position = pos + 1;
                }
                else
                {
                    reply.message = reader.ReadString();
                }
                return reply;
            }

            public int Serialize(object obj)
            {
                if (obj == null)
                    throw new ArgumentNullException(nameof(obj));
                SerializeObject(obj, obj.GetType());
                return (int)stream.Position;
            }

            public object Deserialize()
            {
                return DeserializeObject();
            }

            private void SerializeObject(object obj, Type type)
            {
                if (obj == null)
                {
                    writer.Write((byte)TypeCode.Empty);
                    return;
                }
                if (type == typeof(object))
                {
                    type = obj.GetType();
                }
                byte typeCode = (byte)Type.GetTypeCode(type);
                writer.Write(typeCode);
                if (typeCode != (byte)TypeCode.Object)
                {
                    SerializePrimitive(obj, typeCode);
                    return;
                }
                var typeInfo = GetTypeInfo(type);
                WriteName(typeInfo.TypeName);
                var rank = typeInfo.ArrayRank;
                if (rank > 0)
                {
                    SerializeArray(obj, type, rank);
                    return;
                }
                SerializeMembers(obj, type);
            }

            private object DeserializeObject()
            {
                byte typeCode = reader.ReadByte();
                if (typeCode == (byte)TypeCode.Empty)
                {
                    return null;
                }
                if (typeCode != (byte)TypeCode.Object)
                {
                    return DeserializePrimitive(typeCode);
                }
                var typeName = ReadName();
                var nameType = ResolveType(typeName);
                if (nameType.Rank > 0)
                {
                    if (nameType.Type != null)
                    {
                        return DeserializeArray(nameType.Type, nameType.ElementName, nameType.Rank);
                    }
                    return DeserializeUnkownArray(nameType.ElementName, nameType.Rank);
                }
                if (nameType.Type != null)
                {
                    return DeserializeMembers(nameType.Type, nameType.GenNames);
                }
                return DeserializeUnkownMembers();
            }

            private void SerializePrimitive(object obj, int typeCode)
            {
                switch ((TypeCode)typeCode)
                {
                    case TypeCode.Boolean: writer.Write((bool)obj); break;
                    case TypeCode.Byte: writer.Write((byte)obj); break;
                    case TypeCode.SByte: writer.Write((sbyte)obj); break;
                    case TypeCode.Char: writer.Write((char)obj); break;
                    case TypeCode.Int16: writer.Write((short)obj); break;
                    case TypeCode.UInt16: writer.Write((ushort)obj); break;
                    case TypeCode.Int32: writer.Write((int)obj); break;
                    case TypeCode.UInt32: writer.Write((uint)obj); break;
                    case TypeCode.Int64: writer.Write((long)obj); break;
                    case TypeCode.UInt64: writer.Write((ulong)obj); break;
                    case TypeCode.Single: writer.Write((float)obj); break;
                    case TypeCode.Double: writer.Write((double)obj); break;
                    case TypeCode.Decimal: writer.Write((decimal)obj); break;
                    case TypeCode.String: writer.Write((string)obj); break;
                    case TypeCode.DateTime: writer.Write(((DateTime)obj).Ticks); break;
                    default:
                        Type type = obj.GetType();
                        throw new SerializationException($"{type.FullName}, TypeCode {typeCode}", type.Assembly.FullName);
                }
            }

            private object DeserializePrimitive(int typeCode)
            {
                switch ((TypeCode)typeCode)
                {
                    case TypeCode.Boolean: return reader.ReadBoolean();
                    case TypeCode.Byte: return reader.ReadByte();
                    case TypeCode.SByte: return reader.ReadSByte();
                    case TypeCode.Char: return reader.ReadChar();
                    case TypeCode.Int16: return reader.ReadInt16();
                    case TypeCode.UInt16: return reader.ReadUInt16();
                    case TypeCode.Int32: return reader.ReadInt32();
                    case TypeCode.UInt32: return reader.ReadUInt32();
                    case TypeCode.Int64: return reader.ReadInt64();
                    case TypeCode.UInt64: return reader.ReadUInt64();
                    case TypeCode.Single: return reader.ReadSingle();
                    case TypeCode.Double: return reader.ReadDouble();
                    case TypeCode.Decimal: return reader.ReadDecimal();
                    case TypeCode.String: return reader.ReadString();
                    case TypeCode.DateTime: return DateTime.FromBinary(reader.ReadInt64());
                    default:
                        throw new DeserializeException($"TypeCode {typeCode}", "");
                }
            }

            private void SerializeDict(SerializerDict dictObj)
            {
                writer.Write(dictObj.Count);
                var elementType = dictObj.GetElementType();
                if (elementType == typeof(object))
                {
                    foreach (var element in dictObj)
                    {
                        writer.Write(element.Key);
                        SerializeObject(element.Value, elementType);
                    }
                    return;
                }
                if (elementType.IsArray)
                {
                    var eleRank = elementType.GetArrayRank();
                    foreach (var element in dictObj)
                    {
                        writer.Write(element.Key);
                        SerializeArrayElement(element.Value, elementType, eleRank);
                    }
                    return;
                }
                var typeCode = Type.GetTypeCode(elementType);
                if (typeCode != TypeCode.Object)
                {
                    foreach (var element in dictObj)
                    {
                        writer.Write(element.Key);
                        SerializePrimitive(element.Value, (int)typeCode);
                    }
                    return;
                }
                var membersInfo = WriteMembersInfo(elementType);
                foreach (var element in dictObj)
                {
                    writer.Write(element.Key);
                    SerializeMemberElement(element.Value, membersInfo);
                }
            }

            private void DeserializeDict(SerializerDict dictObj, string elementName)
            {
                var totalElements = reader.ReadInt32();
                if (elementName == "System.Object")
                {
                    for (int i = 0; i < totalElements; i++)
                    {
                        string key = reader.ReadString();
                        object value = DeserializeObject();
                        dictObj.AddValue(key, value);
                    }
                    return;
                }
                var elementType = ResolveType(elementName);
                if (elementType.Rank > 0)
                {
                    for (int i = 0; i < totalElements; i++)
                    {
                        string key = reader.ReadString();
                        object value = DeserializeArrayElement(elementType.Type, elementType.ElementName, elementType.Rank);
                        dictObj.AddValue(key, value);
                    }
                    return;
                }
                var membersInfo = ReadMembersInfo(elementType.Type, out var memberMatch);
                if (membersInfo != null)
                {
                    var typeCode = Type.GetTypeCode(elementType.Type);
                    if (typeCode != TypeCode.Empty && typeCode != TypeCode.Object)
                    {
                        for (int i = 0; i < totalElements; i++)
                        {
                            string key = reader.ReadString();
                            object value = DeserializePrimitive((int)typeCode);
                            dictObj.AddValue(key, value);
                        }
                        return;
                    }
                    for (int i = 0; i < totalElements; i++)
                    {
                        string key = reader.ReadString();
                        object value = DeserializeMemberElement(membersInfo, memberMatch, elementType.GenNames);
                        dictObj.AddValue(key, value);
                    }
                    return;
                }
                for (int i = 0; i < totalElements; i++)
                {
                    string key = reader.ReadString();
                    object value = DeserializeUnkownElement(memberMatch);
                    dictObj.AddValue(key, value);
                }
            }

            private void SerializeDict2(SerializerDict2 dictObj)
            {
                writer.Write(dictObj.Count);
                var keyCode = dictObj.GetKeyCode();
                var valueType = dictObj.GetElementType();
                if (valueType == typeof(object))
                {
                    foreach (var element in dictObj)
                    {
                        SerializePrimitive(element.Key, (int)keyCode);
                        SerializeObject(element.Value, valueType);
                    }
                    return;
                }
                if (valueType.IsArray)
                {
                    var eleRank = valueType.GetArrayRank();
                    foreach (var element in dictObj)
                    {
                        SerializePrimitive(element.Key, (int)keyCode);
                        SerializeArrayElement(element.Value, valueType, eleRank);
                    }
                    return;
                }
                var typeCode = Type.GetTypeCode(valueType);
                if (typeCode != TypeCode.Object)
                {
                    foreach (var element in dictObj)
                    {
                        SerializePrimitive(element.Key, (int)keyCode);
                        SerializePrimitive(element.Value, (int)typeCode);
                    }
                    return;
                }
                var membersInfo = WriteMembersInfo(valueType);
                foreach (var element in dictObj)
                {
                    SerializePrimitive(element.Key, (int)keyCode);
                    SerializeMemberElement(element.Value, membersInfo);
                }
            }

            private void DeserializeDict2(SerializerDict2 dictObj, string keyName, string valueName)
            {
                var keyCode = dictObj.GetKeyCode();
                var totalElements = reader.ReadInt32();
                if (valueName == "System.Object")
                {
                    for (int i = 0; i < totalElements; i++)
                    {
                        object key = DeserializePrimitive((int)keyCode);
                        object value = DeserializeObject();
                        dictObj.AddValue(key, value);
                    }
                    return;
                }
                var elementType = ResolveType(valueName);
                if (elementType.Rank > 0)
                {
                    for (int i = 0; i < totalElements; i++)
                    {
                        object key = DeserializePrimitive((int)keyCode);
                        object value = DeserializeArrayElement(elementType.Type, elementType.ElementName, elementType.Rank);
                        dictObj.AddValue(key, value);
                    }
                    return;
                }
                var membersInfo = ReadMembersInfo(elementType.Type, out var memberMatch);
                if (membersInfo != null)
                {
                    var typeCode = Type.GetTypeCode(elementType.Type);
                    if (typeCode != TypeCode.Empty && typeCode != TypeCode.Object)
                    {
                        for (int i = 0; i < totalElements; i++)
                        {
                            object key = DeserializePrimitive((int)keyCode);
                            object value = DeserializePrimitive((int)typeCode);
                            dictObj.AddValue(key, value);
                        }
                        return;
                    }
                    for (int i = 0; i < totalElements; i++)
                    {
                        object key = DeserializePrimitive((int)keyCode);
                        object value = DeserializeMemberElement(membersInfo, memberMatch, elementType.GenNames);
                        dictObj.AddValue(key, value);
                    }
                    return;
                }
                for (int i = 0; i < totalElements; i++)
                {
                    object key = DeserializePrimitive((int)keyCode);
                    object value = DeserializeUnkownElement(memberMatch);
                    dictObj.AddValue(key, value);
                }
            }

            private void SerializeList(SerializerList listObj)
            {
                writer.Write(listObj.Count);
                var elementType = listObj.GetElementType();
                if (elementType == typeof(object))
                {
                    foreach (var element in listObj)
                    {
                        SerializeObject(element, elementType);
                    }
                    return;
                }
                if (elementType.IsArray)
                {
                    var eleRank = elementType.GetArrayRank();
                    foreach (var element in listObj)
                    {
                        SerializeArrayElement(element, elementType, eleRank);
                    }
                    return;
                }
                var typeCode = Type.GetTypeCode(elementType);
                if (typeCode != TypeCode.Object)
                {
                    foreach (var element in listObj)
                    {
                        SerializePrimitive(element, (int)typeCode);
                    }
                    return;
                }
                var membersInfo = WriteMembersInfo(elementType);
                foreach (var element in listObj)
                {
                    SerializeMemberElement(element, membersInfo);
                }
            }

            private void DeserializeList(SerializerList listObj, string elementName)
            {
                var totalElements = reader.ReadInt32();
                if (elementName == "System.Object")
                {
                    if (totalElements < 0 || totalElements * IntPtr.Size > stream.Length - stream.Position)
                    {
                        throw new DeserializeException("List数量异常", "");
                    }
                    listObj.Capacity(totalElements);
                    for (int i = 0; i < totalElements; i++)
                    {
                        object value = DeserializeObject();
                        listObj.AddValue(value);
                    }
                    return;
                }
                var elementType = ResolveType(elementName);
                if (elementType.Rank > 0)
                {
                    if (totalElements < 0 || totalElements * IntPtr.Size > stream.Length - stream.Position)
                    {
                        throw new DeserializeException("List数量异常", "");
                    }
                    listObj.Capacity(totalElements);
                    for (int i = 0; i < totalElements; i++)
                    {
                        object value = DeserializeArrayElement(elementType.Type, elementType.ElementName, elementType.Rank);
                        listObj.AddValue(value);
                    }
                    return;
                }
                var membersInfo = ReadMembersInfo(elementType.Type, out var memberMatch);
                if (membersInfo != null)
                {
                    var elementSize = GetElementSize(elementType.Type, out var typeCode);
                    if (totalElements < 0 || totalElements * elementSize > stream.Length - stream.Position)
                    {
                        throw new DeserializeException("List数量异常", "");
                    }
                    listObj.Capacity(totalElements);
                    if (typeCode != TypeCode.Empty && typeCode != TypeCode.Object)
                    {
                        for (int i = 0; i < totalElements; i++)
                        {
                            object value = DeserializePrimitive((int)typeCode);
                            listObj.AddValue(value);
                        }
                        return;
                    }
                    for (int i = 0; i < totalElements; i++)
                    {
                        object value = DeserializeMemberElement(membersInfo, memberMatch, elementType.GenNames);
                        listObj.AddValue(value);
                    }
                    return;
                }
                if (totalElements < 0 || totalElements * IntPtr.Size > stream.Length - stream.Position)
                {
                    throw new DeserializeException("List数量异常", "");
                }
                listObj.Capacity(totalElements);
                for (int i = 0; i < totalElements; i++)
                {
                    object value = DeserializeUnkownElement(memberMatch);
                    listObj.AddValue(value);
                }
            }

            private void SerializeArray(object arrayObj, Type type, int rank)
            {
                var array = (Array)arrayObj;
                var elementType = type.GetElementType();
                var lengths = new int[rank];
                var lowerBounds = new int[rank];
                int totalElements = 1;
                for (int i = 0; i < rank; i++)
                {
                    var length = lengths[i] = array.GetLength(i);
                    writer.Write(length);
                    totalElements *= length;
                }
                for (int i = 0; i < rank; i++)
                {
                    var lowerBound = lowerBounds[i] = array.GetLowerBound(i);
                    writer.Write(lowerBound);
                }
                if (totalElements != 0)
                {
                    if (!WriteBytesMD(array, elementType, rank))
                    {
                        SerializeArrayElements(array, totalElements, elementType, lowerBounds, lengths);
                    }
                }
            }

            static private int GetElementSize(Type type, out TypeCode typeCode)
            {
                typeCode = Type.GetTypeCode(type);
                switch (typeCode)
                {
                    case TypeCode.Boolean:
                    case TypeCode.Byte:
                    case TypeCode.SByte:
                        return 1;
                    case TypeCode.Char:
                    case TypeCode.Int16:
                    case TypeCode.UInt16:
                        return 2;
                    case TypeCode.Int32:
                    case TypeCode.UInt32:
                    case TypeCode.Single:
                        return 4;
                    case TypeCode.Int64:
                    case TypeCode.UInt64:
                    case TypeCode.Double:
                    case TypeCode.DateTime:
                        return 8;
                    case TypeCode.String:
                        return IntPtr.Size;
                    case TypeCode.Decimal:
                        return sizeof(decimal);
                    case TypeCode.Object:
                        if (type.IsValueType)
                        {
                            return SizeOf(type, false);
                        }
                        return IntPtr.Size;
                }
                return int.MaxValue;
            }

            private object DeserializeArray(Type type, string elementName, int rank)
            {
                var elementType = type.GetElementType();
                var elementSize = GetElementSize(elementType, out var _);
                var lengths = new int[rank];
                var lowerBounds = new int[rank];
                long totalElements = 1;
                for (int i = 0; i < rank; i++)
                {
                    var len = reader.ReadInt32();
                    if (len < 0)
                    {
                        throw new DeserializeException($"{type.FullName} Length错误", type.Assembly.FullName);
                    }
                    totalElements *= len;
                    lengths[i] = len;
                    if (totalElements * elementSize > stream.Length - stream.Position)
                    {
                        throw new DeserializeException($"{type.FullName} Length错误", type.Assembly.FullName);
                    }
                }
                for (int i = 0; i < rank; i++)
                {
                    var lowerBound = lowerBounds[i] = reader.ReadInt32();
                    if (lowerBound < 0)
                    {
                        throw new DeserializeException($"{type.FullName} LowerBound错误", type.Assembly.FullName);
                    }
                }
                var array = Array.CreateInstance(elementType, lengths, lowerBounds);
                if (totalElements != 0)
                {
                    if (!ReadBytesMD(array, elementType, rank))
                    {
                        DeserializeArrayElements(array, (int)totalElements, elementName, lowerBounds, lengths);
                    }
                }
                return array;
            }

            private object DeserializeUnkownArray(string elementName, int rank)
            {
                var lengths = new int[rank];
                var lowerBounds = new int[rank];
                long totalElements = 1;
                for (int i = 0; i < rank; i++)
                {
                    var len = reader.ReadInt32();
                    if (len < 0)
                    {
                        throw new DeserializeException("Length错误", "");
                    }
                    totalElements *= len;
                    lengths[i] = len;
                    if (totalElements > stream.Length - stream.Position)
                    {
                        throw new DeserializeException("Length错误", "");
                    }
                }
                for (int i = 0; i < rank; i++)
                {
                    var lowerBound = lowerBounds[i] = reader.ReadInt32();
                    if (lowerBound < 0)
                    {
                        throw new DeserializeException("LowerBound错误", "");
                    }
                }
                var array = Array.CreateInstance(typeof(object), lengths, lowerBounds);
                if (totalElements != 0)
                {
                    DeserializeArrayElements(array, (int)totalElements, elementName, lowerBounds, lengths);
                }
                return array;
            }

            private void SerializeArrayElements(Array array, int totalElements, Type elementType, int[] lowerBounds, int[] lengths)
            {
                if (totalElements == 1)
                {
                    var element = array.GetValue(lowerBounds);
                    SerializeObject(element, elementType);
                    return;
                }
                var indices = new int[lowerBounds.Length];
                lowerBounds.CopyTo(indices, 0);
                if (elementType == typeof(object))
                {
                    for (int i = 0; i < totalElements; i++)
                    {
                        var element = array.GetValue(indices);
                        SerializeObject(element, elementType);
                        IncrementIndices(indices, lowerBounds, lengths);
                    }
                    return;
                }
                var typeInfo = GetTypeInfo(elementType);
                var elementRank = typeInfo.ArrayRank;
                if (elementRank > 0)
                {
                    for (int i = 0; i < totalElements; i++)
                    {
                        var element = array.GetValue(indices);
                        SerializeArrayElement(element, elementType, elementRank);
                        IncrementIndices(indices, lowerBounds, lengths);
                    }
                    return;
                }
                var typeCode = Type.GetTypeCode(elementType);
                if (typeCode != TypeCode.Object)
                {
                    for (int i = 0; i < totalElements; i++)
                    {
                        var element = array.GetValue(indices);
                        SerializePrimitive(element, (int)typeCode);
                        IncrementIndices(indices, lowerBounds, lengths);
                    }
                    return;
                }
                var membersInfo = WriteMembersInfo(elementType);
                if ((!matchMember || membersInfo.IsInternal) && membersInfo.TupleSize > 0)
                {
                    WriteTupleArray(array, totalElements, membersInfo.TupleSize);
                    return;
                }
                for (int i = 0; i < totalElements; i++)
                {
                    var element = array.GetValue(indices);
                    SerializeMemberElement(element, membersInfo);
                    IncrementIndices(indices, lowerBounds, lengths);
                }
            }

            private void DeserializeArrayElements(Array array, int totalElements, string elementName, int[] lowerBounds, int[] lengths)
            {
                if (totalElements == 1)
                {
                    var element = DeserializeObject();
                    array.SetValue(element, lowerBounds);
                    return;
                }
                var indices = new int[lowerBounds.Length];
                lowerBounds.CopyTo(indices, 0);
                if (elementName == "System.Object")
                {
                    for (int i = 0; i < totalElements; i++)
                    {
                        var element = DeserializeObject();
                        array.SetValue(element, indices);
                        IncrementIndices(indices, lowerBounds, lengths);
                    }
                    return;
                }
                var elementType = ResolveType(elementName);
                if (elementType.Rank > 0)
                {
                    for (int i = 0; i < totalElements; i++)
                    {
                        object instance = DeserializeArrayElement(elementType.Type, elementType.ElementName, elementType.Rank);
                        array.SetValue(instance, indices);
                        IncrementIndices(indices, lowerBounds, lengths);
                    }
                    return;
                }
                var typeCode = Type.GetTypeCode(elementType.Type);
                if (typeCode != TypeCode.Empty && typeCode != TypeCode.Object)
                {
                    for (int i = 0; i < totalElements; i++)
                    {
                        object instance = DeserializePrimitive((int)typeCode);
                        array.SetValue(instance, indices);
                        IncrementIndices(indices, lowerBounds, lengths);
                    }
                    return;
                }
                var membersInfo = ReadMembersInfo(elementType.Type, out var memberMatch);
                if (membersInfo != null)
                {
                    if ((!matchMember || membersInfo.IsInternal) && membersInfo.TupleSize > 0)
                    {
                        ReadTupleArray(array, totalElements, membersInfo.TupleSize);
                        return;
                    }
                    for (int i = 0; i < totalElements; i++)
                    {
                        object instance = DeserializeMemberElement(membersInfo, memberMatch, elementType.GenNames);
                        array.SetValue(instance, indices);
                        IncrementIndices(indices, lowerBounds, lengths);
                    }
                    return;
                }
                for (int i = 0; i < totalElements; i++)
                {
                    object instance = DeserializeUnkownElement(memberMatch);
                    array.SetValue(instance, indices);
                    IncrementIndices(indices, lowerBounds, lengths);
                }
            }

            private void SerializeArrayElement(object element, Type elementType, int rank)
            {
                if (element == null)
                {
                    writer.Write(false);
                }
                else
                {
                    writer.Write(true);
                    SerializeArray(element, elementType, rank);
                }
            }

            private void WriteTupleArray(object array, int totalElements, int tupleSize)
            {
                byte[] dstBuf = stream.GetBuffer();
                int pos = (int)stream.Position;
                int dstOrg = origin + pos;
                int dstLen = dstBuf.Length - dstOrg;
                int srcLen = totalElements * tupleSize;
                if (srcLen > dstLen)
                    throw new IOException("写入流长度溢出");
                var gchandle = GCHandle.Alloc(array, GCHandleType.Pinned);
                var src = gchandle.AddrOfPinnedObject();
                fixed (byte* dst = dstBuf)
                    CopyBytes(dst + dstOrg, (byte*)src, srcLen);
                gchandle.Free();
                stream.Position = pos + srcLen;
            }

            private void ReadTupleArray(object array, int totalElements, int tupleSize)
            {
                byte[] srcBuf = stream.GetBuffer();
                int pos = (int)stream.Position;
                int srcOrg = origin + pos;
                int srcLen = srcBuf.Length - srcOrg;
                int dstLen = totalElements * tupleSize;
                if (dstLen > srcLen)
                    throw new IOException("读取流长度溢出");
                var gchandle = GCHandle.Alloc(array, GCHandleType.Pinned);
                var dst = gchandle.AddrOfPinnedObject();
                fixed (byte* src = srcBuf)
                    CopyBytes((byte*)dst, src + srcOrg, dstLen);
                gchandle.Free();
                stream.Position = pos + dstLen;
            }

            private void SerializeMemberElement(object element, MembersInfo membersInfo)
            {
                if (element == null)
                {
                    writer.Write(false);
                    return;
                }
                writer.Write(true);
                switch (membersInfo.GenType)
                {
                    case GenType.Dict:
                        SerializeDict((SerializerDict)element);
                        break;
                    case GenType.Dict2:
                        SerializeDict2((SerializerDict2)element);
                        break;
                    case GenType.List:
                        SerializeList((SerializerList)element);
                        break;
                    default:
                        foreach (var memberInfo in membersInfo.Members)
                        {
                            var value = memberInfo.GetValue(element);
                            SerializeObject(value, memberInfo.MemberType);
                        }
                        break;
                }
            }

            private object DeserializeArrayElement(Type type, string elementName2, int rank)
            {
                if (!reader.ReadBoolean())
                {
                    return null;
                }
                if (type != null)
                {
                    return DeserializeArray(type, elementName2, rank);
                }
                return DeserializeUnkownArray(elementName2, rank);
            }

            private object DeserializeMemberElement(MembersInfo membersInfo, tuple<int, string>[] memberMatch, string[] genNames)
            {
                if (!reader.ReadBoolean())
                {
                    return null;
                }
                object instance = membersInfo.New();
                switch (membersInfo.GenType)
                {
                    case GenType.Dict:
                        DeserializeDict((SerializerDict)instance, genNames[0]);
                        break;
                    case GenType.Dict2:
                        DeserializeDict2((SerializerDict2)instance, genNames[0], genNames[1]);
                        break;
                    case GenType.List:
                        DeserializeList((SerializerList)instance, genNames[0]);
                        break;
                    default:
                        if (memberMatch == null)
                        {
                            foreach (var memberInfo in membersInfo.Members)
                            {
                                var value = DeserializeObject();
                                memberInfo.SetValue(instance, value);
                            }
                        }
                        else
                        {
                            for (int j = 0; j < memberMatch.Length; j++)
                            {
                                var value = DeserializeObject();
                                var k = memberMatch[j].value1;
                                if (k != -1)
                                {
                                    membersInfo.Members[k].SetValue(instance, value);
                                }
                                else if (membersInfo.IsLostTuple)
                                {
                                    ((LostTuple)instance).AddLost(memberMatch[j].value2, value);
                                }
                            }
                        }
                        break;
                }
                return instance;
            }

            private object DeserializeUnkownElement(tuple<int, string>[] memberMatch)
            {
                if (!reader.ReadBoolean())
                {
                    return null;
                }
                SerializerDict instance = new DictTuple<object>();
                for (int j = 0; j < memberMatch.Length; j++)
                {
                    var value = DeserializeObject();
                    instance.AddValue(memberMatch[j].value2, value);
                }
                return instance;
            }

            private MembersInfo WriteMembersInfo(Type elementType)
            {
                var membersInfo = GetMembersInfo(elementType);
                if (matchMember && !membersInfo.IsInternal)
                {
                    writer.Write((byte)membersInfo.Members.Length);
                    foreach (var memberInfo in membersInfo.Members)
                    {
                        WriteName(memberInfo.MemberName);
                    }
                }
                return membersInfo;
            }

            private MembersInfo ReadMembersInfo(Type elementType, out tuple<int, string>[] memberMatch)
            {
                if (elementType == null)
                {
                    var memberCount = reader.ReadByte();
                    memberMatch = new tuple<int, string>[memberCount];
                    for (int i = 0; i < memberCount; i++)
                    {
                        var memberName = ReadName();
                        memberMatch[i] = tuple.make(i, memberName);
                    }
                    return null;
                }
                else
                {
                    MembersInfo membersInfo = GetMembersInfo(elementType);
                    if (!matchMember || membersInfo.IsInternal)
                    {
                        memberMatch = null;
                        return membersInfo;
                    }
                    var memberCount = reader.ReadByte();
                    memberMatch = new tuple<int, string>[memberCount];
                    int members = membersInfo.Members.Length;
                    int offset = (members + 31) >> 5;
                    uint* bitsSet = stackalloc uint[offset];
                    for (int i = 0; i < offset; i++)
                    {
                        bitsSet[i] = 0;
                    }
                    offset = 0;
                    for (int i = 0; i < memberCount; i++)
                    {
                        var memberName = ReadName();
                        memberMatch[i] = tuple.make(-1, memberName);
                        for (int j = 0; j < members; j++)
                        {
                            int k = offset + j;
                            if (k >= members)
                            {
                                k -= members;
                            }
                            int idx = k >> 5;
                            uint bit = 1u << (k & 0x1F);
                            if ((bitsSet[idx] & bit) == 0)
                            {
                                var member = membersInfo.Members[k];
                                if (memberName == member.MemberName)
                                {
                                    memberMatch[i] = tuple.make(k, memberName);
                                    bitsSet[idx] |= bit;
                                    offset = k + 1;
                                    break;
                                }
                            }
                        }
                    }
                    return membersInfo;
                }
            }

            static private void IncrementIndices(int[] indices, int[] lowerBounds, int[] lengths)
            {
                var rank = indices.Length;
                for (int dimension = rank - 1; dimension >= 0; dimension--)
                {
                    indices[dimension]++;
                    if (indices[dimension] < lowerBounds[dimension] + lengths[dimension])
                    {
                        break;
                    }
                    indices[dimension] = lowerBounds[dimension];
                }
            }

            private void SerializeMembers(object obj, Type type)
            {
                var membersInfo = GetMembersInfo(type);
                switch (membersInfo.GenType)
                {
                    case GenType.Dict:
                        SerializeDict((SerializerDict)obj);
                        return;
                    case GenType.Dict2:
                        SerializeDict2((SerializerDict2)obj);
                        break;
                    case GenType.List:
                        SerializeList((SerializerList)obj);
                        return;
                }
                if (!matchMember || membersInfo.IsInternal)
                {
                    if (membersInfo.TupleSize > 0)
                    {
                        WriteTupleArray(obj, 1, membersInfo.TupleSize);
                    }
                    else
                    {
                        foreach (var memberInfo in membersInfo.Members)
                        {
                            var value = memberInfo.GetValue(obj);
                            SerializeObject(value, memberInfo.MemberType);
                        }
                    }
                }
                else
                {
                    writer.Write((byte)membersInfo.Members.Length);
                    foreach (var memberInfo in membersInfo.Members)
                    {
                        WriteName(memberInfo.MemberName);
                        var value = memberInfo.GetValue(obj);
                        SerializeObject(value, memberInfo.MemberType);
                    }
                }
            }

            private object DeserializeMembers(Type type, string[] genNames)
            {
                var membersInfo = GetMembersInfo(type);
                var instance = membersInfo.New();
                switch (membersInfo.GenType)
                {
                    case GenType.Dict:
                        DeserializeDict((SerializerDict)instance, genNames[0]);
                        return instance;
                    case GenType.Dict2:
                        DeserializeDict2((SerializerDict2)instance, genNames[0], genNames[1]);
                        return instance;
                    case GenType.List:
                        DeserializeList((SerializerList)instance, genNames[0]);
                        return instance;
                }
                if (!matchMember || membersInfo.IsInternal)
                {
                    if (membersInfo.TupleSize > 0)
                    {
                        ReadTupleArray(instance, 1, membersInfo.TupleSize);
                    }
                    else
                    {
                        foreach (var memberInfo in membersInfo.Members)
                        {
                            var value = DeserializeObject();
                            memberInfo.SetValue(instance, value);
                        }
                    }
                }
                else
                {
                    var memberCount = reader.ReadByte();
                    int members = membersInfo.Members.Length;
                    int offset = (members + 31) >> 5;
                    uint* bitsSet = stackalloc uint[offset];
                    for (int i = 0; i < offset; i++)
                    {
                        bitsSet[i] = 0;
                    }
                    offset = 0;
                    for (int i = 0; i < memberCount; i++)
                    {
                        var memberName = ReadName();
                        var value = DeserializeObject();
                        bool isLost = true;
                        for (int j = 0; j < members; j++)
                        {
                            int k = offset + j;
                            if (k >= members)
                            {
                                k -= members;
                            }
                            int idx = k >> 5;
                            uint bit = 1u << (k & 0x1F);
                            if ((bitsSet[idx] & bit) == 0)
                            {
                                var member = membersInfo.Members[k];
                                if (memberName == member.MemberName)
                                {
                                    member.SetValue(instance, value);
                                    bitsSet[idx] |= bit;
                                    offset = k + 1;
                                    isLost = false;
                                    break;
                                }
                            }
                        }
                        if (isLost && membersInfo.IsLostTuple)
                        {
                            ((LostTuple)instance).AddLost(memberName, value);
                        }
                    }
                }
                return instance;
            }

            private object DeserializeUnkownMembers()
            {
                SerializerDict instance = new DictTuple<object>();
                var memberCount = reader.ReadByte();
                for (int i = 0; i < memberCount; i++)
                {
                    var memberName = ReadName();
                    var value = DeserializeObject();
                    instance.AddValue(memberName, value);
                }
                return instance;
            }

            private NameType ResolveType(string typeName)
            {
                var nameType = ResolveType_(typeName);
                if (!matchMember && (nameType.Type == null || nameType.GenUndefined))
                {
                    throw new DeserializeException($"未定义的类型:{typeName}", "");
                }
                return nameType;
            }

            static private NameType ResolveType_(string typeName)
            {
                if (string.IsNullOrEmpty(typeName))
                {
                    throw new DeserializeException("", "");
                }
                if (TryGetCache(_nameTypeCache, typeName, out var cacheType))
                {
                    return cacheType;
                }
                int firstBracket = new TypeInfo { TypeName = typeName }.FirstBracket;
                int firstGeneric = typeName.IndexOf('<');
                bool arrayType = firstBracket > 0;
                bool genericType = firstGeneric > 0;
                if (!arrayType && !genericType)
                {
                    return new NameType(typeName, null, null, false);
                }
                bool genUndefined = false;
                string[] genNames = null;
                Type resolvedType = null;
                if (genericType)
                {
                    string elementName = null;
                    if (arrayType)
                    {
                        elementName = typeName.Substring(0, firstBracket);
                        if (TryGetCache(_nameTypeCache, elementName, out cacheType))
                        {
                            resolvedType = cacheType.Type;
                            genUndefined |= cacheType.GenUndefined;
                            goto make_array;
                        }
                    }
                    string genericName = typeName.Substring(0, firstGeneric);
                    if (!TryGetCache(_nameTypeCache, genericName, out cacheType))
                    {
                        return new NameType(typeName, null, null, false);
                    }
                    if (cacheType.GenNames == null || cacheType.GenNames.Length == 0)
                    {
                        throw new DeserializeException($"模板类型未定义:{typeName}", "");
                    }
                    resolvedType = cacheType.Type;
                    int genCount = 0;
                    int layer = 1;
                    int baseLen = arrayType ? firstBracket : typeName.Length;
                    for (int i = firstGeneric + 1; i < baseLen; i++)
                    {
                        switch (typeName[i])
                        {
                            case '<':
                                layer++;
                                break;
                            case '>':
                                layer--;
                                if (layer == 0)
                                {
                                    genCount++;
                                }
                                else if (layer < 0)
                                {
                                    throw new DeserializeException(typeName, "");
                                }
                                break;
                        }
                    }
                    if (layer != 0)
                    {
                        throw new DeserializeException(typeName, "");
                    }
                    if (cacheType.GenNames.Length != genCount)
                    {
                        throw new DeserializeException($"模板类型数量不一致:{typeName}", "");
                    }
                    Type[] genArgs = new Type[genCount];
                    genNames = new string[genCount];
                    int begin = firstGeneric;
                    genCount = 0;
                    layer = 1;
                    for (int i = firstGeneric + 1; i < baseLen; i++)
                    {
                        switch (typeName[i])
                        {
                            case '<':
                                if (layer == 0)
                                {
                                    begin = i;
                                }
                                layer++;
                                break;
                            case '>':
                                layer--;
                                if (layer == 0)
                                {
                                    string genArg = typeName.Substring(begin + 1, i - begin - 1);
                                    var genType = ResolveType_(genArg);
                                    var tempType = genType.Type;
                                    if (tempType == null)
                                    {
                                        genUndefined = true;
                                        tempType = typeof(object);
                                    }
                                    else
                                    {
                                        genUndefined |= genType.GenUndefined;
                                    }
                                    genArgs[genCount] = tempType;
                                    genNames[genCount] = genArg;
                                    genCount++;
                                }
                                break;
                        }
                    }
                    resolvedType = resolvedType.MakeGenericType(genArgs);
                    if (!arrayType)
                    {
                        var nameType = new NameType(typeName, resolvedType, genNames, genUndefined);
                        TryAddCache(_nameTypeCache, typeName, nameType);
                        return nameType;
                    }
                    TryAddCache(_nameTypeCache, elementName, new NameType(elementName, resolvedType, genNames, genUndefined));
                }
                else
                {
                    string elementName = typeName.Substring(0, firstBracket);
                    if (!TryGetCache(_nameTypeCache, elementName, out cacheType))
                    {
                        return new NameType(typeName, null, null, false);
                    }
                    resolvedType = cacheType.Type;
                }
make_array:
                int lastBracket = firstBracket;
                for (int i = lastBracket + 1; i < typeName.Length; i++)
                {
                    char c = typeName[i];
                    switch (c)
                    {
                        case '[':
                            if (lastBracket != -1)
                            {
                                throw new DeserializeException(typeName, "");
                            }
                            lastBracket = i;
                            break;
                        case ']':
                            if (lastBracket == -1)
                            {
                                throw new DeserializeException(typeName, "");
                            }
                            int rank = i - lastBracket;
                            if (rank > 4)
                            {
                                throw new DeserializeException(typeName, "");
                            }
                            lastBracket = -1;
                            resolvedType = resolvedType.MakeArrayType(rank);
                            break;
                        case ',':
                            if (lastBracket == -1)
                            {
                                throw new DeserializeException(typeName, "");
                            }
                            break;
                        default:
                            throw new DeserializeException(typeName, "");
                    }
                }
                if (lastBracket != -1)
                {
                    throw new DeserializeException(typeName, "");
                }
                {
                    var nameType = new NameType(typeName, resolvedType, genNames, genUndefined);
                    TryAddCache(_nameTypeCache, typeName, nameType);
                    return nameType;
                }
            }

            static private TypeInfo GetTypeInfo(Type type)
            {
                if (!_typeInfoCache.TryGetValue(type, out var typeInfo))
                {
                    typeInfo = new TypeInfo(type);
                    var rank = typeInfo.ArrayRank;
                    if (rank != 0)
                    {
                        if (rank < 0)
                        {
                            throw new SerializationException($"{type.FullName} 数组异常", type.Assembly.FullName);
                        }
                        var deep = typeInfo.ArrayDeep;
                        if (deep > 4)
                        {
                            throw new SerializationException($"{type.FullName} 数组异常", type.Assembly.FullName);
                        }
                        if (deep <= 0)
                        {
                            throw new SerializationException("未知异常", "");
                        }
                    }
                    _typeInfoCache.TryAdd(type, typeInfo);
                }
                return typeInfo;
            }

            static private bool CheckType(Type type, out bool isBaseType)
            {
                Type baseType = type;
                bool isArray = type.IsArray;
                bool arrayIt = baseType.IsArray;
                while (arrayIt)
                {
                    baseType = baseType.GetElementType();
                    arrayIt = baseType.IsArray;
                }
                switch (Type.GetTypeCode(baseType))
                {
                    case TypeCode.SByte:
                    case TypeCode.Byte:
                    case TypeCode.Int16:
                    case TypeCode.UInt16:
                    case TypeCode.Int32:
                    case TypeCode.UInt32:
                    case TypeCode.Int64:
                    case TypeCode.UInt64:
                    case TypeCode.Single:
                    case TypeCode.Double:
                        isBaseType = !isArray;
                        return true;
                    case TypeCode.Boolean:
                    case TypeCode.Char:
                    case TypeCode.Decimal:
                    case TypeCode.DateTime:
                    case TypeCode.String:
                        isBaseType = false;
                        return true;
                    case TypeCode.Object:
                        if (isBaseType = baseType.IsValueType)
                        {
                            foreach (Type genType in baseType.GetGenericArguments())
                            {
                                if (!CheckType(genType, out bool genIsBaseType))
                                {
                                    isBaseType = false;
                                    return false;
                                }
                                isBaseType &= genIsBaseType;
                            }
                        }
                        if (baseType == typeof(object))
                        {
                            return true;
                        }
                        return Attribute.IsDefined(baseType, typeof(ParamTuple), false);
                    default:
                        isBaseType = false;
                        return false;
                }
            }

            static private MembersInfo GetMembersInfo(Type type, bool update = true)
            {
                if (TryGetCache(_memberCache, type, out var cached, update))
                {
                    return cached;
                }
                var typeNameAttr = (ParamTuple)Attribute.GetCustomAttribute(type, typeof(ParamTuple), false);
                if (typeNameAttr == null)
                {
                    throw new SerializationException(type.FullName, type.Assembly.FullName);
                }
                bool isValueType = type.IsValueType;
                bool allBase = isValueType;
                var fields = GetFields(type);
                var properties = GetProperties(type);
                var members = new MemberInfo[fields.Count + properties.Count];
                for (int i = 0; i < fields.Count; i++)
                {
                    var fieldType = fields[i].value1.FieldType;
                    if (!CheckType(fieldType, out bool isBaseType))
                    {
                        throw new SerializationException($"{type.FullName}.{fields[i].value1.Name}", type.Assembly.FullName);
                    }
                    allBase &= isBaseType;
                    members[i].MemberName = fields[i].value2;
                    members[i].MemberType = fieldType;
                    members[i].GetValue = CreateObjectGetter(fields[i].value1);
                    members[i].SetValue = CreateObjectSetter(fields[i].value1);
                }
                for (int i = 0, off = fields.Count; i < properties.Count; i++)
                {
                    var propertyType = properties[i].value1.PropertyType;
                    if (!CheckType(propertyType, out bool isBaseType))
                    {
                        throw new SerializationException($"{type.FullName}.{properties[i].value1.Name}", type.Assembly.FullName);
                    }
                    allBase &= isBaseType;
                    members[off + i].MemberName = properties[i].value2;
                    members[off + i].MemberType = propertyType;
                    members[off + i].GetValue = CreateObjectGetter(properties[i].value1.GetGetMethod(true));
                    members[off + i].SetValue = CreateObjectSetter(properties[i].value1.GetSetMethod(true));
                }
                MembersInfo result = new MembersInfo();
                result.IsInternal = typeNameAttr.Internal;
                result.IsLostTuple = type.IsSubclassOf(typeof(LostTuple));
                result.TupleSize = allBase ? SizeOf(type, false) : -1;
                result.New = CreateDefinedNew(type);
                result.Members = members;
                result.GenType = CheckGenericTuple(type);
                TryAddCache(_memberCache, type, result, update);
                return result;
            }
        }
    }
}
